<?php
/**
 * Created by PhpStorm.
 * User: jaylen
 * Date: 2020-11-23
 * Time: 13:58
 */

namespace app\common\model\traits;

use app\common\enum\OrderEnum;
use app\common\exception\OrderException;
use app\common\exception\ParameterException;
use app\common\validate\Order as Validate;
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Alignment;
use PhpOffice\PhpSpreadsheet\Style\NumberFormat;
use think\facade\App;
use think\facade\Request;

trait HandleOrderExcelData
{
    /**
     * 生成全部订单Excel表格数据
     * @param $data
     */
    public static function generateAllOrderDataExcel($data)
    {
        $validate = new Validate();
        if (!$validate->scene('generate_all_data_excel')->check($data)) {
            throw new ParameterException([
                'msg' => $validate->getError(),
            ]);
        }

        // 获取对应类型的全部订单数据
        $order = static::with(['user','address','product','express' => function($query) {
            $query->with(['express_company']);
        }])
            ->field('id,title,address_id,freight,user_id,order_no,out_order_no,amount,refund_amount,type,status,pay_time,delivery_time,order_end_time,refund_create_time,create_time')
            ->where([['type','=',$data['type']]])
            ->order(['create_time' => 'DESC'])
            ->select();
        if ($order->isEmpty()) {
            throw new OrderException([
                'msg' => '需要生成的订单数据为空'
            ]);
        }

        // 格式化status的值
        $order->withAttr('status', function ($value) {
            return self::formatStatusValue($value);
        });

        // 将数据转换为数组
        $order_data = $order->toArray();
        // 生成excel的临时文件名
        $file_name = 'all_order_data_' . time();

        // 准备生成Excel文件的数据
        $title = ['id','订单编号','订单退款编号','订单名称','购买用户','产品规格','物流公司','物流编号','订单价格','订单邮费','退款费用','订单状态','创建时间','支付时间','发货时间','退款时间','结束时间'];
        $data = self::recombinantAllOrderData($order_data);

        try {
            self::createAllOrderDataExcel($title, $data, $file_name, '图鸟商店');
        } catch (\Exception $e) {
            throw new OrderException([
                'msg' => $e->getMessage()
            ]);
        }
    }

    public static function generateDeliveryOrderData($data)
    {
        $validate = new Validate();
        if (!$validate->scene('generate_delivery_data_excel')->check($data)) {
            throw new ParameterException([
                'msg' => $validate->getError(),
            ]);
        }

        // 获取对应类型的全部订单数据
        $order = static::with(['user','address','product'])
            ->field('id,title,address_id,freight,user_id,order_no,amount,type,pay_time,create_time')
            ->where([['type','=',$data['type']],['status','=',OrderEnum::PAY_SUCCESS]])
            ->order(['create_time' => 'DESC'])
            ->select();
        if ($order->isEmpty()) {
            throw new OrderException([
                'msg' => '需要生成的订单数据为空'
            ]);
        }
        // 将数据转换为数组
        $order_data = $order->toArray();
        // 生成excel的临时文件名
        $file_name = 'delivery_order_data_' . time();

        // 准备生成Excel文件的数据
        $title = ['id','订单编号','订单名称','商品规格','购买用户','订单价格','订单邮费','收件人名称','收件人联系方式','收货地址','创建时间','支付时间','物流公司编号','物流单号'];
        $data = self::recombinantDeliveryOrderData($order_data);

        try {
            self::createDeliveryOrderDataExcel($title, $data, $file_name, '图鸟商店');
        } catch (\Exception $e) {
            throw new OrderException([
                'msg' => $e->getMessage()
            ]);
        }
    }

    /**
     * 格式化订单状态的值
     * @param $value
     * @return string
     */
    private static function formatStatusValue($value)
    {
        switch ($value) {
            case 1:
                return '创建订单';
            case 2:
                return '支付成功';
            case 3:
                return '支付失败';
            case 4:
                return '关闭订单';
            case 5:
                return '发起退款';
            case 6:
                return '退款成功';
            case 7:
                return '退款异常';
            case 8:
                return '退款关闭';
            case 9:
                return '已发货';
            case 10:
                return '用户发起退款';
            case 11:
                return '订单结束';
            case 12:
                return '订单已经提交，但是没有支付';
            case 13:
                return '用户取消退款';
            case 14:
                return '快递已被用户签收';
        }
    }

    /**
     * 重组全部订单数据
     * @param $order_data
     * @return array
     */
    private static function recombinantAllOrderData($order_data)
    {
        $data = [];
        foreach ($order_data as $order_item) {
            $specs_data = '';
            if (isset($order_item['product']) && !empty($order_item['product'])) {
                $specs = array_column($order_item['product'],'specs_data');
                $specs = array_map(function ($item) {
                    $item_str = '';
                    foreach ($item as $i_key => $i_value) {
                        $item_str .= $i_key . ':' . $i_value;
                        $item_str .= ';';
                    }
                    return substr($item_str, 0, -1);
                }, $specs);
                foreach ($specs as $specs_value) {
                    $specs_data .= $specs_value . PHP_EOL;
                }
            }
            $data[] = [
                0 => $order_item['id'],
                1 => $order_item['order_no'],
                2 => $order_item['out_order_no'],
                3 => $order_item['title'],
                4 => $order_item['user']['nick_name'],
                5 => $specs_data,
                6 => (isset($order_item['express']) && !empty($order_item['express'])) ? $order_item['express']['express_company']['name'] : '',
                7 => (isset($order_item['express']) && !empty($order_item['express'])) ? $order_item['express']['express_no'] : '',
                8 => $order_item['amount'],
                9 => $order_item['freight'],
                10 => $order_item['refund_amount'],
                11 => $order_item['status'],
                12 => $order_item['create_time'],
                13 => $order_item['pay_time'],
                14 => $order_item['delivery_time'],
                15 => $order_item['refund_create_time'],
                16 => $order_item['order_end_time']
            ];
        }

        return $data;
    }

    /**
     * 重组待发货的订单数据
     * @param $order_data
     */
    private static function recombinantDeliveryOrderData($order_data)
    {
        $data = [];
        foreach ($order_data as $order_item) {
            // 规格数据
            $specs_data = '';
            if (isset($order_item['product']) && !empty($order_item['product'])) {
                $specs = array_column($order_item['product'], 'specs_data');
                $specs = array_map(function ($item) {
                    $item_str = '';
                    foreach ($item as $i_key => $i_value) {
                        $item_str .= $i_key . ':' . $i_value;
                        $item_str .= ';';
                    }
                    return substr($item_str, 0, -1);
                }, $specs);
                foreach ($specs as $specs_value) {
                    $specs_data .= $specs_value . PHP_EOL;
                }
            }
            // 收件人相关信息
            $receipts_user = '';
            $receipts_phone = '';
            $receipts_address = '';
            if (isset($order_item['address']) && !empty($order_item['address'])) {
                $address = $order_item['address'];
                $receipts_user = $address['user_name'];
                $receipts_phone = $address['tel_number'];
                $receipts_address = $address['province_name'] . ' ' . $address['city_name'] . ' ' . $address['county_name'] . ' ' . $address['detail_info'];
            }

            $data[] = [
                0 => $order_item['id'],
                1 => $order_item['order_no'],
                2 => $order_item['title'],
                3 => $specs_data,
                4 => $order_item['user']['nick_name'],
                5 => $order_item['amount'],
                6 => $order_item['freight'],
                7 => $receipts_user,
                8 => $receipts_phone,
                9 => $receipts_address,
                10 => $order_item['create_time'],
                11 => $order_item['pay_time'],
                12 => '',
                13 => '',
            ];
        }

        return $data;
    }

    /**
     * 创建全部订单Excel数据
     * @param $excel_title
     * @param $excel_data
     * @param string $file_name
     * @param string $sheet_name
     */
    private static function createAllOrderDataExcel($excel_title, $excel_data, $file_name = '', $sheet_name = 'sheet1')
    {
        // 创建excel文件对象
        $spreadSheet = new Spreadsheet();
        // 创建工作表
        $workSheet = $spreadSheet->getActiveSheet();
        // 设置工作表的名称
        $workSheet->setTitle($sheet_name);

        // 设置单元格内容
        // 表头
        foreach ($excel_title as $title_key => $title_value) {
            $workSheet->setCellValueByColumnAndRow($title_key+1, 1, $title_value);
        }

        // 表内容
        // 从第二行开始
        $row = 2;
        foreach ($excel_data as $data_value) {
            $column = 1;
            foreach ($data_value as $value_item) {
                $workSheet->setCellValueByColumnAndRow($column, $row, $value_item);
                $column++;
            }
            $row++;
        }

        // 设置物流编号的格式为数值没有小数点
        $workSheet->getStyle('H2:H' . ($row-1))->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_NUMBER);

        // 设置对应列的列宽
        $workSheet->getColumnDimension('B')->setWidth(20);
        $workSheet->getColumnDimension('C')->setWidth(20);
        $workSheet->getColumnDimension('D')->setWidth(17);
        $workSheet->getColumnDimension('E')->setWidth(17);
        $workSheet->getColumnDimension('G')->setWidth(17);
        $workSheet->getColumnDimension('H')->setWidth(17);
        $workSheet->getColumnDimension('L')->setWidth(30);
        $workSheet->getColumnDimension('M')->setWidth(20);
        $workSheet->getColumnDimension('N')->setWidth(20);
        $workSheet->getColumnDimension('O')->setWidth(20);
        $workSheet->getColumnDimension('P')->setWidth(20);
        $workSheet->getColumnDimension('Q')->setWidth(20);

        // 设置内容为居中对齐
        $style_array = [
            'alignment' => [
                'horizontal' => Alignment::HORIZONTAL_CENTER
            ]
        ];
        $workSheet->getStyle('A1:Q' . ($row - 1))->applyFromArray($style_array);

        self::exportExcel($spreadSheet, $file_name);
    }

    /**
     * 创建发货订单Excel数据
     * @param $excel_title
     * @param $excel_data
     * @param string $file_name
     * @param string $sheet_name
     */
    private static function createDeliveryOrderDataExcel($excel_title, $excel_data, $file_name = '', $sheet_name = 'sheet1')
    {
        // 创建excel文件对象
        $spreadSheet = new Spreadsheet();
        // 创建工作表
        $workSheet = $spreadSheet->getActiveSheet();
        // 设置工作表的名称
        $workSheet->setTitle($sheet_name);

        // 设置单元格内容
        // 表头
        foreach ($excel_title as $title_key => $title_value) {
            $workSheet->setCellValueByColumnAndRow($title_key+1, 1, $title_value);
        }

        // 表内容
        // 从第二行开始
        $row = 2;
        foreach ($excel_data as $data_value) {
            $column = 1;
            foreach ($data_value as $value_item) {
                $workSheet->setCellValueByColumnAndRow($column, $row, $value_item);
                $column++;
            }
            $row++;
        }

        // 设置收件人联系方法的格式为数值没有小数点
        $workSheet->getStyle('I2:I' . ($row-1))->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_NUMBER);
        // 设置物流编号的格式为数值没有小数点
        $workSheet->getStyle('N2:N' . ($row-1))->getNumberFormat()->setFormatCode(NumberFormat::FORMAT_NUMBER);

        // 设置对应列的列宽
        $workSheet->getColumnDimension('B')->setWidth(20);
        $workSheet->getColumnDimension('C')->setWidth(20);
        $workSheet->getColumnDimension('D')->setWidth(17);
        $workSheet->getColumnDimension('E')->setWidth(17);
        $workSheet->getColumnDimension('H')->setWidth(17);
        $workSheet->getColumnDimension('I')->setWidth(17);
        $workSheet->getColumnDimension('J')->setWidth(40);
        $workSheet->getColumnDimension('K')->setWidth(20);
        $workSheet->getColumnDimension('L')->setWidth(20);
        $workSheet->getColumnDimension('M')->setWidth(14);
        $workSheet->getColumnDimension('N')->setWidth(20);

        // 设置内容为居中对齐
        $style_array = [
            'alignment' => [
                'horizontal' => Alignment::HORIZONTAL_CENTER
            ]
        ];
        $workSheet->getStyle('A1:N' . ($row - 1))->applyFromArray($style_array);

        self::exportExcel($spreadSheet, $file_name);
    }

    /**
     * 导出Excel文件
     * @param Spreadsheet $spreadSheet
     * @param $file_name
     */
    private static function exportExcel(Spreadsheet $spreadSheet, $file_name)
    {
        // 输出内容到浏览器
        ob_end_clean();
        ob_start();

        // 设置header
        header('Access-Control-Allow-Credentials: true');
        header('Access-Control-Allow-Methods: GET, POST, PUT,DELETE,OPTIONS,PATCH');
        header("Access-Control-Allow-Headers: Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With");
        header('Access-Control-Allow-Origin:'.Request::header('origin'));
        header("Access-Control-Expose-Headers: Content-Disposition");
        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        header('Content-Disposition: attachment;filename="'.$file_name.'.xlsx"');
        header('Cache-Control: max-age=0');
        // 按照指定格式生成Excel文件
        $writer = IOFactory::createWriter($spreadSheet, 'Xlsx');
        $writer->save('php://output');
        exit();
//        $file_path = App::getRootPath() . 'public/storage/order_temp_excel/' . $file_name . 'xlsx';
//        $writer->save($file_path);
//        // 读取文件内容
//        $content = file_get_contents($file_path);
//        exit($content);
    }


}